/*
 *  BreakIteratorBasedTokeniser.java
 *
 *  Copyright (c) 2006, 2007
 *  Knowledge Information & Data Management Laboratory
 *  Sirindhorn International Institute of Technology
 *  Thammasat University
 * 
 *  Arthit Suriyawongkul
 *  art <at> siit.net
 *
 *  art, 27/12/2006
 */

package net.siit.gate;

import java.util.*;
import java.util.Locale;
import java.text.BreakIterator;
import java.io.BufferedReader;
import java.io.StringReader;

import com.ibm.icu.text.DictionaryBasedBreakIterator;

import gate.*;
import gate.creole.*;
import gate.creole.tokeniser.DefaultTokeniser;
import gate.util.*;



/**
 * This class is the implementation of the resource BITOKENISER.
 */
public class BreakIteratorBasedTokeniser extends DefaultTokeniser {
//public class BreakIteratorBasedTokeniser  extends AbstractProcessingResource implements ProcessingResource {

    //private BreakIterator bi = null;
    private com.ibm.icu.text.BreakIterator bi = null;
    private Locale locale = null;

    /*
    * this method gets called whenever an object of this
    * class is created either from GATE GUI or if
    * initiated using Factory.createResource() method.
    */
    public Resource init() throws ResourceInstantiationException {
        fireProgressChanged(0);
        fireStatusChanged("Creating a tokeniser");

        if ((localeName == null) || (localeName.trim().length() == 0)) {
            fireStatusChanged("Locale unspecified, use default.");
            locale = Locale.getDefault();
        } else {
            locale = new Locale(localeName);
        }
        fireProgressChanged(50);

        bi = DictionaryBasedBreakIterator.getWordInstance(locale);

        if (bi== null) {
            fireStatusChanged("Cannot instantiate break iterator");
            throw new ResourceInstantiationException("Cannot instantiate break iterator");
        }

        fireStatusChanged("Instantiated " + bi.getClass().getName() + " (" + locale.getDisplayName() + ")");
        fireProgressChanged(100);
        fireProcessFinished();

        return this;
    }

    /*
    * this method should provide the actual functionality of the PR
    * (from where the main execution begins). This method
    * gets called when user click on the RUN button in the
    * GATE GUIs application window.
    */
    public void execute() throws ExecutionException {
        fireProgressChanged(0);

        if (document == null) {
            throw new ExecutionException("No document to process!");
        }

        fireStatusChanged("Tokenising " + document.getName() + "...");

        if (annotationSetName != null && annotationSetName.trim().length() == 0) {
            annotationSetName = null;
        }

        AnnotationSet as = (annotationSetName == null) ?
                            document.getAnnotations() :
                            document.getAnnotations(annotationSetName);

        //System.err.println("AS: " + as.getName() + " (" + as.size() + ")");

        int nllen = 1;
        String nl = (String) document.getFeatures().get("docNewLineType");
        if (nl.equalsIgnoreCase("CRLF") || nl.equalsIgnoreCase("LFCR")) {
            nllen = 2;
        }

        BufferedReader in = new BufferedReader(
                new StringReader(document.getContent().toString()));
        String line = null;
        try {
            int start, end;
            long index = 0;
            String tokenString;
            String annotName;
            while ((line = in.readLine()) != null) {
                start = 0;
                end   = 0;
                bi.setText(line);
                while ((end = bi.next()) != BreakIterator.DONE) {
                    tokenString = line.substring(start, end);

                    FeatureMap features = Factory.newFeatureMap();
                    features.put(TOKEN_STRING_FEATURE_NAME, tokenString);  // "string"
                    features.put(TOKEN_LENGTH_FEATURE_NAME, tokenString.length());  // "length"

                    if (tokenString.trim().length() == 0) {
                        annotName = SPACE_TOKEN_ANNOTATION_TYPE;  // "SpaceToken"
                    } else {
                        annotName = TOKEN_ANNOTATION_TYPE;  // "Token"
                    }

                    as.add(Long.valueOf(index+start), Long.valueOf(index+end), annotName, features);

                    start = end;
                }
                index += line.length() + nllen;
            }
        }
        catch (Exception ex) {
            throw new ExecutionException(ex);
        }

        // dereference
        //in.close();
        as = null;

        fireStatusChanged("Tokenisation complete!");
        fireProgressChanged(100);
        fireProcessFinished();
    }

    /* this method is called to reinitialize the resource */
    public void reInit() throws ResourceInstantiationException {
        this.init();
    }

    /*
    * There are two types of parameters
    * 1. Init time parameters values for these parameters need to be
    * provided at the time of initializing a new resource and these values are
    * not supposed to be changed.
    * 2. Runtime parameters - values for these parameters are provided at the time
    * of executing the PR. These are runtime parameters and can be
    * changed before starting the execution
    * (i.e. before you click on the "RUN" button in the GATE GUI)
    * It is must to provide setter and getter methods for every such
    * parameter declared in the creole.xml.
    *
    * for example to set a value for outputAnnotationSetName
    */
    private String annotationSetName;
    private String localeName;

    // getters, setters
    public String getAnnotationSetName() {
        return annotationSetName;
    }
    public void setAnnotationSetName(String annotationSetName) {
        this.annotationSetName = annotationSetName;
    }

    public String getLocaleName() {
        return localeName;
    }
    public void setLocaleName(String localeName) {
        this.localeName = localeName;
    }

} // class BreakIteratorBasedTokeniser